package net.entelijan.config.impl2;

import java.awt.Component;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;

import net.entelijan.config.ICobeanConfig;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.ClassUtils;

public class DefaultCobeanConfig implements ICobeanConfig {

	private List<IBinderFactory> binderFactories;

	private static Log log = LogFactory.getLog(DefaultCobeanConfig.class);

	@Override
	public <T> T bind(T model, Object view, Object config) {
		T re = model;
		List<IEnhancedComponent> enhancedComponents = createEnhancedComponents(view);
		List<IBinder> binders = new ArrayList<IBinder>();
		for (IBinderFactory bf : binderFactories) {
			bf.addBinders(binders, enhancedComponents);
		}
		for (IBinder b : binders) {
			re = b.bind(re, config);
		}
		return re;
	}

	private List<IEnhancedComponent> createEnhancedComponents(Object view) {
		List<IEnhancedComponent> re = new ArrayList<IEnhancedComponent>();
		BeanWrapper wview = new BeanWrapperImpl(view);
		for (PropertyDescriptor pd : wview.getPropertyDescriptors()) {
			String propName = pd.getName();
			Class<?> propertyType = wview.getPropertyType(propName);
			if (propertyType != null
					&& ClassUtils.isAssignable(Component.class, propertyType)
					&& wview.isReadableProperty(propName)) {
				Component comp = (Component) wview.getPropertyValue(propName);
				if (comp != null) {
					re.add(createEnhancedComponent(comp, propName));
				} else {
					log.info("Could not create enhanced component for '"
							+ propName + "' because the component is 'null'");
				}
			} else {
				log.debug("Could not create enhanced component for '"
						+ propName + "' because it is not an AWT Component");
			}
		}
		return re;
	}

	private IEnhancedComponent createEnhancedComponent(final Component comp,
			final String propName) {
		return new IEnhancedComponent() {

			@Override
			public Component getComponent() {
				return comp;
			}

			@Override
			public List<List<String>> getPathes() {
				return PathUtil.splitToPossiblePathes(propName);
			}

		};
	}

	public List<IBinderFactory> getBinderFactories() {
		return binderFactories;
	}

	public void setBinderFactories(List<IBinderFactory> binderFactories) {
		this.binderFactories = binderFactories;
	}

}
